package cn.gyn.gynrpc.demo.provider;

import cn.gyn.gynrpc.core.api.RpcRequest;
import cn.gyn.gynrpc.core.api.RpcResponse;
import cn.gyn.gynrpc.core.config.ProviderConfig;
import cn.gyn.gynrpc.core.config.ProviderProperties;
import cn.gyn.gynrpc.core.config.ApolloChangedListener;
import cn.gyn.gynrpc.core.transport.SpringBootTransport;
import cn.gyn.gynrpc.demo.api.User;
import cn.gyn.gynrpc.demo.api.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 业务
 */
@SpringBootApplication
@RestController
//这里是个import传递，SpringBootTransport
@Import({ProviderConfig.class})
public class GynrpcDemoProviderApplication {
    @Bean
    ApolloChangedListener apolloChangedListener() {
        return new ApolloChangedListener();
    }

    @Autowired
    ProviderProperties providerProperties;

    public static void main(String[] args) {
        SpringApplication.run(GynrpcDemoProviderApplication.class, args);
    }

    // 引入@RestController，暴露一个rest接口，让远程能通过http供客户端调用访问，借用springboot http请求接入能力，来作为RPC入口，即
    // 使用HTTP+JSON 来是实现序列化和通信
    // 其中request和 RpcResponse应该是框架的一部分
    // 根目录“/”
    /*@RequestMapping("/")
    public RpcResponse invoke(@RequestBody RpcRequest request) {
        return providerInvoker.Invoke(request);
        //return new RpcResponse();
    }*/

    @Autowired
    UserService userService;

    /**
     * 用此接口模拟故障接口突然恢复正常，并触发探活恢复服务
     * @param ports
     * @return
     */
    @RequestMapping("/ports")
    public RpcResponse invoke(@RequestParam("ports") String ports) {
        userService.setTimeoutPorts(ports);
        RpcResponse<String> response = new RpcResponse<>();
        response.setStatus(true);
        response.setData("OK:" + ports);
        return response;
    }

    /**
     * 获取metas
     * @return
     */
    @RequestMapping("/metas")
    public String metas() {
        //测试一下如果apollo配置修改，触发刷新providerProperties后，这种写法的metas和providerProperties的hashcode是否会变化。
        Map<String, String> metas = providerProperties.getMetas();
        System.out.println("System.identityHashCode(metas)===>"+System.identityHashCode(metas));
        System.out.println("System.identityHashCode(providerProperties)===>"+System.identityHashCode(providerProperties));

        return providerProperties.getMetas().toString();
    }


    @Autowired
    SpringBootTransport transport;

    /**
     * 此方法模拟RPC的客户端请求
     * ApplicationRunner是Spring Boot框架中的一个接口，用于在Spring Boot应用程序启动后执行特定的操作。它会在spring容器都启动好了之后执行
     * 它允许开发人员编写自定义的应用程序启动逻辑，以便在应用程序完全启动时执行一些初始化工作或者触发某些操作
     *
     * @return
     */
    @Bean
    ApplicationRunner ProviderRun() {
        return x -> {
            //providerProperties.getMetas().forEach((k, v) -> System.out.println(k + ":" + v));
            testAll();
        };
    }

    private void testAll() {
        //  test 1 parameter method
        System.out.println("Provider Case 1. >>===[基本测试：1个参数]===");
        RpcRequest request = new RpcRequest();
        request.setService("cn.gyn.gynrpc.demo.api.UserService");
        request.setMethodSign("findById@1_int");
        request.setArgs(new Object[]{100});

        RpcResponse<Object> rpcResponse = transport.invoke(request);
        System.out.println("return : " + rpcResponse.getData());

        // test 2 parameters method
        System.out.println("Provider Case 2. >>===[基本测试：2个参数]===");
        RpcRequest request1 = new RpcRequest();
        request1.setService("cn.gyn.gynrpc.demo.api.UserService");
        request1.setMethodSign("findById@2_int_java.lang.String");
        request1.setArgs(new Object[]{100, "2paramsFindById"});

        RpcResponse<Object> rpcResponse1 = transport.invoke(request1);
        System.out.println("return : " + rpcResponse1.getData());

        // test 3 for List<User> method&parameter
        System.out.println("Provider Case 3. >>===[复杂测试：参数类型为List<User>]===");
        RpcRequest request3 = new RpcRequest();
        request3.setService("cn.gyn.gynrpc.demo.api.UserService");
        request3.setMethodSign("getList@1_java.util.List");
        List<User> userList = new ArrayList<>();
        userList.add(new User(100, "gyn100"));
        userList.add(new User(101, "gyn101"));
        request3.setArgs(new Object[]{userList});
        RpcResponse<Object> rpcResponse3 = transport.invoke(request3);
        System.out.println("return : " + rpcResponse3.getData());

        // test 4 for Map<String, User> method&parameter
        System.out.println("Provider Case 4. >>===[复杂测试：参数类型为Map<String, User>]===");
        RpcRequest request4 = new RpcRequest();
        request4.setService("cn.gyn.gynrpc.demo.api.UserService");
        request4.setMethodSign("getMap@1_java.util.Map");
        Map<String, User> userMap = new HashMap<>();
        userMap.put("P100", new User(100, "gyn100"));
        userMap.put("P101", new User(101, "gyn101"));
        request4.setArgs(new Object[]{userMap});
        RpcResponse<Object> rpcResponse4 = transport.invoke(request4);
        System.out.println("return : " + rpcResponse4.getData());

        // test 5 for traffic control
        System.out.println("Provider Case 5. >>===[复杂测试：测试流量并发控制]===");
        /*RpcRequest request5 = new RpcRequest();
        request5.setService("cn.gyn.gynrpc.demo.api.UserService");
        request5.setMethodSign("findById@1_int");
        request5.setArgs(new Object[]{100});
        for (int i = 0; i < 120; i++) {
            try {
                Thread.sleep(1000);
                RpcResponse<Object> r = transport.invoke(request5);
                System.out.println(i + " ***>>> " +r.getData());
            } catch (RpcException e) {
                // ignore
                System.out.println(i + " ***>>> " +e.getMessage() + " -> " + e.getErrcode());
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }*/
    }
}
